
//
// 101103 - AH - Created.
// 101104 - AH - throwUknownElementParseException(String).
// 101110a- AH - getMandatoryAttr(String, Attributes).
// 101110b- AH - throwUnexpectedElementParseException(Object, String).
// 101128 - AH - throwParseException(Exception).
// 101212 - AH - (Bien) getErrorMessage(Exception).
// 110717 - AH - getMandatoryIntAttr(String, Attributes).
// 110724 - AH - (Bien *) getBooleanAttr(String, Attributes). 
//

package org.soekrat.engine.io;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * <p>
 *   Base class for XML handlers used in XML parsing.
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC) 
 */
public abstract class XmlHandler extends DefaultHandler 
{
  protected Locator m_loc=null;

  // Specified in DocumentHandler.
  public void setDocumentLocator(Locator l){ m_loc=l; }
  
  /**
   * <p>
   *   Gets mandatory XML element attribute value.
   * </p>
   * @param name  Attribute name.
   * @param attrs {@link Attributes}.
   * @return Value.
   * @throws SAXException If not found.
   */
  protected final String getMandatoryAttr(String name, Attributes attrs) 
    throws SAXException
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (attrs==null)
    {
      throw new NullPointerException("attrs");
    }
    
    String val=attrs.getValue(name);

    if (val==null)
    {
      throwParseException("missing attribute : "+name);
    }

    return val;
  }
  
  /**
   * <p>
   *   Gets XML element attribute value as an [@code boolean} which default
   *   value is {@code false}.
   * </p>
   * @param name  Attribute name.
   * @param attrs {@link Attributes}.
   * @return {@code false} if attribute not found or {@code true} if value is
   *         equal to "true" ignoring case else returns {@code false}.
   */
  protected final boolean getBooleanAttr(String name, Attributes attrs)
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (attrs==null)
    {
      throw new NullPointerException("attrs");
    }
    
    String value=attrs.getValue(name);
    return value==null ? false : value.equalsIgnoreCase("true");
  }
  
  /**
   * <p>
   *   Gets mandatory XML element attribute value that is an {@code int} value.
   * </p>
   * @param name  Attribute name.
   * @param attrs {@link Attributes}.
   * @return Value.
   * @throws SAXException If not found or could not be parsed as an {@code int}.
   */
  protected final int getMandatoryIntAttr(String name, Attributes attrs)
    throws SAXException
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    if (attrs==null)
    {
      throw new NullPointerException("attrs");
    }
    
    String val=getMandatoryAttr(name, attrs);
    try
    {
      return Integer.parseInt(val);
    }
    catch (NumberFormatException nfx)
    {
      throwParseException("could not parse attribute : "+name+" as int");
      return -1; // Can never happen.
    }
  }
  
  /**
   * <p>
   *   Throws parse exception when known element encountered when should not.
   * </p>
   * @param mustExists An object that must exist if ok to encounter 
   *                   {@code element}.
   * @param element    Name on element encountered.
   * @throws SAXException If {@code mustExists==null};
   */
  protected final void throwUnexpectedElementParseException(Object mustExists, 
    String element) throws SAXException
  {
    if (mustExists==null) 
      throwParseException("did not expect element : "+element);      
  }

  /**
   * <p>
   *   Throws parse exception when unknown element encountered.
   * </p>
   * @param element Name of unknown element.
   * @throws SAXException Created exception.
   */
  protected final void throwUknownElementParseException(String element) 
    throws SAXException
  {
    throwParseException("uknown element : "+element);  
  }
  
  /**
   * <p>
   *   Throws a parse exception.
   * </p>
   * @param msg Error message.
   * @throws SAXException Created exception.
   */
  protected final void throwParseException(String msg) throws SAXException
  {
    StringBuilder sb=new StringBuilder();
    if (m_loc!=null)
    {
      sb.append("line : ").append(m_loc.getLineNumber()).append(" : ");  
    }
    sb.append(msg);
    throw new SAXException(sb.toString());
  }
  
  /**
   * <p>
   *   Throws a parse exception.
   * </p>
   * @param x Cause.
   * @throws SAXException Created exception.
   */
  protected final void throwParseException(Exception x) throws SAXException
  {
    SAXException saxx=new SAXException(getErrorMessage(x));
    saxx.initCause(x);
    throw saxx;
  }
  
  /**
   * <p>
   *   Generates error message for parse exceptions, error message will try
   *   including line number.
   * </p>
   * @param x Parse error cause.
   * @return Error message.
   */
  public final String getErrorMessage(Exception x)
  {
    if (x==null)
    {
      throw new NullPointerException("x");
    }
    
    StringBuilder sb=new StringBuilder();
    if (m_loc!=null)
    {
      sb.append("line : ").append(m_loc.getLineNumber()).append(" : ");  
    }
    
    String msg=x.getLocalizedMessage();
    msg=(msg==null) ? "" : msg.trim();
    
    if (msg.length()>0)
    {
      sb.append(msg).append(" (").append(x.getClass().getName()).append(")");  
    }
    else
    {
      sb.append(x.getClass().getName());
    }
    
    return sb.toString();
  }
  
}
